﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using UnityEngine;
using UnityEngine.Video;

namespace ResLibary
{
    /// <summary>
    /// Asset下的资源
    /// </summary>
    public class AssetsLibary : MonoBehaviour, ILibaryHandle
    {
        private static AssetsLibary play_singleton = default(AssetsLibary);
#if UNITY_EDITOR
        private static AssetsLibary edit_singleton = default(AssetsLibary);
#endif
        private static object s_objectLock = new object();
        public static AssetsLibary Instance
        {
            get
            {
#if UNITY_EDITOR
                if (!ResLibaryConfig.isPlaying)
                {
                    if (AssetsLibary.play_singleton != null)
                    {
                        AssetsLibary.play_singleton = null;
                    }
                    if (AssetsLibary.edit_singleton == null)
                    {
                        object obj;
                        Monitor.Enter(obj = AssetsLibary.s_objectLock);//加锁防止多线程创建单例
                        try
                        {
                            if (AssetsLibary.edit_singleton == null)
                            {
                                AssetsLibary.edit_singleton = ((default(AssetsLibary) == null) ? Activator.CreateInstance<AssetsLibary>() : default(AssetsLibary));//创建单例的实例
                            }
                        }
                        finally
                        {
                            Monitor.Exit(obj);
                        }
                    }
                    return AssetsLibary.edit_singleton;
                }
                else
                {
                    if (AssetsLibary.edit_singleton != null)
                    {
                        AssetsLibary.edit_singleton = null;
                    }
                    if (AssetsLibary.play_singleton == null)
                    {
                        object obj;
                        Monitor.Enter(obj = AssetsLibary.s_objectLock);//加锁防止多线程创建单例
                        try
                        {
                            if (AssetsLibary.play_singleton == null)
                            {
                                AssetsLibary.play_singleton = ((default(AssetsLibary) == null) ? Activator.CreateInstance<AssetsLibary>() : default(AssetsLibary));//创建单例的实例
                            }
                        }
                        finally
                        {
                            Monitor.Exit(obj);
                        }
                    }
                    return AssetsLibary.play_singleton;
                }
#else
                if (AssetsLibary.play_singleton == null)
                {
                    object obj;
                    Monitor.Enter(obj = AssetsLibary.s_objectLock);//加锁防止多线程创建单例
                    try
                    {
                        if (AssetsLibary.play_singleton == null)
                        {
                            AssetsLibary.play_singleton = ((default(AssetsLibary) == null) ? Activator.CreateInstance<AssetsLibary>() : default(AssetsLibary));//创建单例的实例
                        }
                    }
                    finally
                    {
                        Monitor.Exit(obj);
                    }
                }
                return AssetsLibary.play_singleton;
#endif
            }
        }

        private List<int> libaryAssetids;
        private List<LibaryAssetSetting> libaryAssets;
        private List<Dictionary<string, Dictionary<string, int>>> assetKeyDic;
        private Dictionary<string, Dictionary<string, UnityEngine.Object>> assetDict;
        public static System.Action<LibaryStateObj> UpdateAssetCallback;
        Thread t;

        private bool _hasLoadAsset = false;
        bool ILibaryHandle.HasLoadAsset { get { return _hasLoadAsset; } }

        public AssetsLibary()
        {
            libaryAssetids = new List<int>();
            libaryAssets = new List<LibaryAssetSetting>();
            assetKeyDic = new List<Dictionary<string, Dictionary<string, int>>>();
            assetDict = new Dictionary<string, Dictionary<string, UnityEngine.Object>>();

        }

        private void InitLibaryAsset(object data)
        {
            try
            {
                List<Dictionary<string, List<string>>> tks = (List<Dictionary<string, List<string>>>)data;
                Dictionary<string, List<string>>[] arr = tks.ToArray();
                for (int i = 0; i < arr.Length; i++)
                {
                    Dictionary<string, List<string>> tk = arr[i];
                    Dictionary<string, Dictionary<string, int>> assetKDic = assetKeyDic[i];
                    foreach (var item in tk)
                    {
                        if (!assetKDic.ContainsKey(item.Key))
                            assetKDic[item.Key] = new Dictionary<string, int>();
                        InitLibaryAssetSetting(item.Key, item.Value, assetKDic[item.Key]);
                    }
                }
            }
            catch (Exception e) { Debug.LogError(e.Message + ":" + e.StackTrace); }
            _hasLoadAsset = true;
        }

        private void InitLibaryAssetSetting(string _type, List<string> list, Dictionary<string, int> assetKDic)
        {

            string[] array = list.ToArray();
            for (int i = 0; i < array.Length; i++)
            {
                string item = array[i];
                if (string.IsNullOrEmpty(item))
                    continue;
                assetKDic[item] = i;
                LibaryStateObj libaryObj = new LibaryStateObj();
                libaryObj.m_Name = item;
                libaryObj.m_Status = LibaryStatusEnum.DIR_ASSETS;
                libaryObj.m_Type = _type;

                if (UpdateAssetCallback != null)
                    UpdateAssetCallback(libaryObj);

            }
        }


        void ILibaryHandle.InsertLibrary(object body)
        {
            _hasLoadAsset = false;
            List<object> lbody = (List<object>)body;
            object[] arr = lbody.ToArray();
            List<Dictionary<string, List<string>>> tks = new List<Dictionary<string, List<string>>>();

            int curIndex = 0;
            for (int i = 0; i < arr.Length; i++)
            {
                object data = arr[i];
                if (data.GetType().Name != "LibaryAssetSetting")
                    continue;
                LibaryAssetSetting assetSetting = (LibaryAssetSetting)data;
                if (libaryAssetids.Contains(assetSetting.settingId))
                    continue;
                tks.Add(new Dictionary<string, List<string>>());

                tks[curIndex][ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_Texture2D]] = new List<string>(assetSetting.texture2dks);
                tks[curIndex][ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_AudioClip]] = new List<string>(assetSetting.audioks);
                tks[curIndex][ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_GameObject]] = new List<string>(assetSetting.prefabks);
                tks[curIndex][ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_Material]] = new List<string>(assetSetting.materialks);
                tks[curIndex][ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_MovieTexture]] = new List<string>(assetSetting.movieTextureks);
                tks[curIndex][ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_RenderTexture]] = new List<string>(assetSetting.renderTextureks);
                tks[curIndex][ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_Sprite]] = new List<string>(assetSetting.spriteks);
                tks[curIndex][ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_TextAsset]] = new List<string>(assetSetting.textAssetks);
                tks[curIndex][ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_VideoClip]] = new List<string>(assetSetting.videoks);
                tks[curIndex][ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_Font]] = new List<string>(assetSetting.fontks);
                tks[curIndex][ResLibaryConfig.ExistType[LibaryTypeEnum.LibaryType_ScriptableObject]] = new List<string>(assetSetting.scriptableObjectks);
                assetKeyDic.Add(new Dictionary<string, Dictionary<string, int>>());
                libaryAssetids.Add(assetSetting.settingId);
                libaryAssets.Add(assetSetting);

                curIndex++;
            }

#if UNITY_EDITOR
                if (!ResLibaryConfig.isPlaying)
                {
         InitLibaryAsset(tks);
                 }
            else{
         if (t != null)
                t.Abort();
            t = new Thread(InitLibaryAsset);
            t.Start(tks);
            }
#else
            if (t != null)
                t.Abort();
            t = new Thread(InitLibaryAsset);
            t.IsBackground = true;
            t.Start(tks);
#endif

        }

        void ILibaryHandle.DeleteLiibrary(string _type, string name)
        {
            if (assetDict.ContainsKey(_type))
            {
                Dictionary<string, UnityEngine.Object> objectDict = assetDict[_type];
                if (objectDict.ContainsKey(name))
                {
                    objectDict.Remove(name);
                }
            }
        }

        string ILibaryHandle.GetTextAsset(string objName)
        {
            TextAsset textAsset = ((ILibaryHandle)this).GetObject<TextAsset>(objName);
            if (textAsset != null)
                return textAsset.text;
            return null;
        }

        GameObject GetGameObject(string objName)
        {
            return ((ILibaryHandle)this).GetObject<GameObject>(objName);
        }

        Texture2D ILibaryHandle.GetTexture2d(string objName)
        {
            return ((ILibaryHandle)this).GetObject<Texture2D>(objName);
        }

        RenderTexture GetRenderTexture(string objName)
        {
            return ((ILibaryHandle)this).GetObject<RenderTexture>(objName);
        }

        Sprite ILibaryHandle.GetSprite(string objName)
        {
            return ((ILibaryHandle)this).GetObject<Sprite>(objName);
        }

        Material GetMatiral(string objName)
        {
            return ((ILibaryHandle)this).GetObject<Material>(objName);
        }

        AudioClip GetAudioClip(string objName)
        {
            return ((ILibaryHandle)this).GetObject<AudioClip>(objName);
        }

        VideoClip GetVideoClip(string objName)
        {
            return ((ILibaryHandle)this).GetObject<VideoClip>(objName);
        }

        MovieTexture GetMovieTexture(string objName)
        {
            return ((ILibaryHandle)this).GetObject<MovieTexture>(objName);
        }

        T ILibaryHandle.GetObject<T>(string objName)
        {
            string _type = "";
            if (!ResLibaryConfig.TryGetTypeName<T>(out _type))
                return null;
            return (T)((ILibaryHandle)this).GetUnityObject(_type, objName);
        }

        UnityEngine.Object ILibaryHandle.GetUnityObject(string _type, string objName)
        {
            if (assetDict.ContainsKey(_type))
            {
                Dictionary<string, UnityEngine.Object> objectDict = assetDict[_type];
                if (objectDict.ContainsKey(objName))
                {
                    UnityEngine.Object t = objectDict[objName];
                    return t;
                }
            }
            LibaryTypeEnum libaryStatusEnum;
            if (!ResLibaryConfig.ExistTypeNameToEnum.TryGetValue(_type, out libaryStatusEnum))
                return null;
            LibaryAssetSetting[] libaries = libaryAssets.ToArray();
            for (int i = 0; i < libaries.Length; i++)
            {
                LibaryAssetSetting libaryAsset = libaries[i];
                Dictionary<string, Dictionary<string, int>> assetKDic = assetKeyDic[i];
                if (!assetKDic[_type].ContainsKey(objName))
                    continue;
                switch (libaryStatusEnum)
                {
                    case LibaryTypeEnum.LibaryType_Texture2D:
                        return libaryAsset.texture2ds[assetKDic[_type][objName]];
                    case LibaryTypeEnum.LibaryType_RenderTexture:
                        return libaryAsset.renderTextures[assetKDic[_type][objName]];
                    case LibaryTypeEnum.LibaryType_MovieTexture:
                        return libaryAsset.movieTextures[assetKDic[_type][objName]];
                    case LibaryTypeEnum.LibaryType_Sprite:
                        return libaryAsset.sprites[assetKDic[_type][objName]];
                    case LibaryTypeEnum.LibaryType_TextAsset:
                        return libaryAsset.textAssets[assetKDic[_type][objName]];
                    case LibaryTypeEnum.LibaryType_Material:
                        return libaryAsset.materials[assetKDic[_type][objName]];
                    case LibaryTypeEnum.LibaryType_GameObject:
                        return libaryAsset.prefabs[assetKDic[_type][objName]];
                    case LibaryTypeEnum.LibaryType_AudioClip:
                        return libaryAsset.audios[assetKDic[_type][objName]];
                    case LibaryTypeEnum.LibaryType_VideoClip:
                        return libaryAsset.videos[assetKDic[_type][objName]];
                    case LibaryTypeEnum.LibaryType_Font:
                        return libaryAsset.fonts[assetKDic[_type][objName]];
                    case LibaryTypeEnum.LibaryType_ScriptableObject:
                        return libaryAsset.scriptableObjects[assetKDic[_type][objName]];

                }
            }
            return null;
        }

        LibaryExistStatusEnum ILibaryHandle.TryGetObject(LibaryTypeEnum libaryTypeEnum, string objName, out object data)
        {
            data = ((ILibaryHandle)this).GetUnityObject(ResLibaryConfig.ExistType[libaryTypeEnum], objName);
            LibaryExistStatusEnum libaryExistStatusEnum = LibaryExistStatusEnum.LibaryExistStatus_UnityEngineObject;
            return libaryExistStatusEnum;
        }

        public void releaseObj(string _type, string objName)
        {

        }

        public void releaseObj(string objName)
        {
        }

        public void releaseObj(LibaryTypeEnum libaryTypeEnum, string objName) { }
        void ILibaryHandle.releaseObj(UnityEngine.Object obj) { }
        void ILibaryHandle.releaseAll()
        {
            libaryAssetids.Clear();
            libaryAssets.Clear();
            assetDict.Clear();
            assetKeyDic.Clear();
#if UNITY_EDITOR
                if (!ResLibaryConfig.isPlaying)
                {
            edit_singleton = null;
                 }
            else{
            play_singleton = null;
            }
#else
            play_singleton = null;
#endif
        }
        void ILibaryHandle.releaseScene()
        {

        }

        public void AddLibary(UnityEngine.Object assetObj)
        {
            string objName = assetObj.name;
            string _type = assetObj.GetType().Name;
            LibaryTypeEnum libaryStatusEnum;
            if (!ResLibaryConfig.ExistTypeNameToEnum.TryGetValue(_type, out libaryStatusEnum))
                return;
            bool found = false;
            LibaryAssetSetting[] libaries = libaryAssets.ToArray();
            for (int i = 0; i < libaries.Length; i++)
            {
                LibaryAssetSetting libaryAsset = libaries[i];
                Dictionary<string, Dictionary<string, int>> assetKDic = assetKeyDic[i];
                if (assetKDic[_type].ContainsKey(objName))
                {
                    found = true;
                    break;
                }
            }

            if (!found)
            {
                if (!assetDict.ContainsKey(_type))
                {
                    assetDict[_type] = new Dictionary<string, UnityEngine.Object>();
                }
                Dictionary<string, UnityEngine.Object> objectDict = assetDict[_type];
                if (!objectDict.ContainsKey(assetObj.name))
                {
                    objectDict[assetObj.name] = assetObj;
                }
                LibaryStateObj libaryObj = new LibaryStateObj();
                libaryObj.m_Name = objName;
                libaryObj.m_Status = LibaryStatusEnum.DIR_ASSETS;
                libaryObj.m_Type = _type;

                if (UpdateAssetCallback != null)
                    UpdateAssetCallback(libaryObj);
            }
        }
    }
}